package com.southminority.ethnic.service.research.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.southminority.ethnic.common.exception.BusinessException;
import com.southminority.ethnic.common.result.PageResult;
import com.southminority.ethnic.controller.research.vo.ResearchProgressVO;
import com.southminority.ethnic.mapper.research.ResearchProgressMapper;
import com.southminority.ethnic.pojo.ResearchProgress;
import com.southminority.ethnic.service.research.ResearchProgressAdminService;
import com.southminority.ethnic.vo.AttachmentFileVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class ResearchProgressAdminServiceImpl implements ResearchProgressAdminService {

    private final ResearchProgressMapper progressMapper;
    private final ObjectMapper objectMapper;

    @Override
    public PageResult<ResearchProgressVO> getProgressPageForAdmin(Integer page, Integer size, String keyword, String stage, String researchField, Integer status) {
        Page<ResearchProgress> pageObj = new Page<>(page, size);
        QueryWrapper<ResearchProgress> wrapper = new QueryWrapper<>();
        if (keyword != null && !keyword.isBlank()) {
            wrapper.and(qw -> qw.like("title", keyword).or().like("description", keyword).or().like("keywords", keyword));
        }
        if (stage != null && !stage.isBlank()) wrapper.eq("stage", stage);
        if (researchField != null && !researchField.isBlank()) wrapper.eq("research_field", researchField);
        if (status != null) wrapper.eq("status", status); else wrapper.ne("status", -1);
        wrapper.orderByDesc("progress_date").orderByDesc("create_time");
        IPage<ResearchProgress> result = progressMapper.selectPage(pageObj, wrapper);
        List<ResearchProgressVO> records = result.getRecords().stream().map(this::toVO).collect(Collectors.toList());
        return PageResult.<ResearchProgressVO>builder()
                .current(result.getCurrent())
                .size(result.getSize())
                .total(result.getTotal())
                .pages(result.getPages())
                .records(records)
                .build();
    }

    @Override
    public ResearchProgressVO getProgressDetailForAdmin(Long id) {
        ResearchProgress entity = progressMapper.selectById(id);
        if (entity == null) throw new BusinessException("研究进展不存在");
        return toVO(entity);
    }

    @Override
    public ResearchProgressVO createProgress(ResearchProgress progress) {
        normalizeJsonFields(progress);
        progress.setCreateTime(LocalDateTime.now());
        progress.setUpdateTime(LocalDateTime.now());
        progressMapper.insert(progress);
        return toVO(progressMapper.selectById(progress.getId()));
    }

    @Override
    public ResearchProgressVO updateProgress(Long id, ResearchProgress progress) {
        ResearchProgress existing = progressMapper.selectById(id);
        if (existing == null) throw new BusinessException("研究进展不存在");
        progress.setId(id);
        normalizeJsonFields(progress);
        progress.setUpdateTime(LocalDateTime.now());
        progressMapper.updateById(progress);
        return toVO(progressMapper.selectById(id));
    }

    @Override
    public boolean deleteProgress(Long id) {
        ResearchProgress existing = progressMapper.selectById(id);
        if (existing == null) return true;
        existing.setStatus(-1);
        existing.setUpdateTime(LocalDateTime.now());
        return progressMapper.updateById(existing) > 0;
    }

    @Override
    public boolean batchDeleteProgress(List<Long> ids) {
        if (ids == null || ids.isEmpty()) return true;
        ids.forEach(this::deleteProgress);
        return true;
    }

    @Override
    public boolean updateProgressStatus(Long id, Integer status) {
        ResearchProgress existing = progressMapper.selectById(id);
        if (existing == null) throw new BusinessException("研究进展不存在");
        existing.setStatus(status);
        existing.setUpdateTime(LocalDateTime.now());
        return progressMapper.updateById(existing) > 0;
    }

    @Override
    public boolean setProgressFeatured(Long id, Integer isFeatured) {
        ResearchProgress existing = progressMapper.selectById(id);
        if (existing == null) throw new BusinessException("研究进展不存在");
        existing.setIsFeatured(isFeatured);
        existing.setUpdateTime(LocalDateTime.now());
        return progressMapper.updateById(existing) > 0;
    }

    @Override
    public boolean setProgressTimeline(Long id, Integer isTimeline) {
        ResearchProgress existing = progressMapper.selectById(id);
        if (existing == null) throw new BusinessException("研究进展不存在");
        existing.setIsTimeline(isTimeline);
        existing.setUpdateTime(LocalDateTime.now());
        return progressMapper.updateById(existing) > 0;
    }

    @Override
    public List<ResearchProgressVO> getAllProgressForAdmin() {
        QueryWrapper<ResearchProgress> wrapper = new QueryWrapper<>();
        wrapper.ne("status", -1).orderByDesc("create_time");
        List<ResearchProgress> list = progressMapper.selectList(wrapper);
        return list.stream().map(this::toVO).collect(Collectors.toList());
    }

    private ResearchProgressVO toVO(ResearchProgress p) {
        ResearchProgressVO vo = new ResearchProgressVO();
        BeanUtils.copyProperties(p, vo);
        try {
            vo.setAchievements(parseStringList(p.getAchievements()));
            vo.setMilestones(parseStringList(p.getMilestones()));
            vo.setParticipants(parseStringList(p.getParticipants()));
            vo.setImageUrls(parseStringList(p.getImageUrls()));
            vo.setAttachmentUrls(parseAttachmentUrls(p.getAttachmentUrls()));
        } catch (Exception e) {
            log.error("convert to VO failed", e);
        }
        return vo;
    }

    private List<String> parseStringList(String json) {
        try {
            if (json == null || json.isBlank()) return Collections.emptyList();
            return objectMapper.readValue(json, new TypeReference<List<String>>() {});
        } catch (Exception e) {
            return Collections.emptyList();
        }
    }

    /**
     * 容错解析附件字段：
     * 1) 优先解析为 List<AttachmentFileVO>
     * 2) 失败则解析为 List<String> 并转换为 AttachmentFileVO(url=字符串, filename=从URL推断)
     * 3) 对于 "[object Object]" 等无效条目直接忽略
     */
    private List<AttachmentFileVO> parseAttachmentUrls(String json) {
        try {
            if (json == null || json.isBlank()) return Collections.emptyList();
            // 尝试按对象列表解析
            return objectMapper.readValue(json,
                    objectMapper.getTypeFactory().constructCollectionType(List.class, AttachmentFileVO.class));
        } catch (Exception ignored) {
            // 回退为字符串列表
            try {
                List<String> urls = objectMapper.readValue(json, new TypeReference<List<String>>() {});
                return urls.stream()
                        .filter(s -> s != null && !s.isBlank() && !"[object Object]".equalsIgnoreCase(s.trim()))
                        .map(this::toAttachment)
                        .collect(Collectors.toList());
            } catch (Exception e) {
                log.error("parse attachmentUrls failed, raw={}", json, e);
                return Collections.emptyList();
            }
        }
    }

    private AttachmentFileVO toAttachment(String url) {
        AttachmentFileVO vo = new AttachmentFileVO();
        vo.setUrl(url);
        // 简单从URL推断文件名
        try {
            String name = url;
            int idxQ = name.indexOf('?');
            if (idxQ > 0) name = name.substring(0, idxQ);
            int idx = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\'));
            if (idx >= 0 && idx < name.length() - 1) name = name.substring(idx + 1);
            vo.setFilename(name);
        } catch (Exception ignored) {
            vo.setFilename(url);
        }
        return vo;
    }

    private void normalizeJsonFields(ResearchProgress p) {
        // 允许前端直接传已是JSON的字符串，或传普通字符串/数组由前端已处理，这里仅保持原样
        // 无需额外处理；关键是不要包含 createTime/updateTime 等只读字段（由DB触发或此处维护）
    }
} 